﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Dracham.MapEditor.Textures;
using System.Linq;
using System.IO;
using Dracham.MapEditor.Maps;
using Dracham.MapEditor.Singleton;
using System.Threading;
using Dracham.MapEditor.TileEvents;
using Dracham.MapEditor.Zones.Events;
using Dracham.MapEditor.Zones.Events.Actions;

namespace Dracham.MapEditor
{
    public partial class frmMain : Form
    {
        private PictureBox selectedPbTile;
        private Boolean mouseMoveInMapTiles = false;
        private MouseButtons pressedMouseButton = MouseButtons.None;
        private Boolean controlIsPressed = false;
        private Zone zone;

        public frmMain()
        {
            InitializeComponent();

            foreach (Control c in Controls)
            {
                c.KeyDown += new KeyEventHandler(frmMain_KeyDown);
                c.KeyUp += new KeyEventHandler(frmMain_KeyDown);
            }
        }

        private void c_KeyUp(object sender, KeyEventArgs e)
        {
            this.controlIsPressed = e.Control;
        }

        private void frmMain_KeyDown(object sender, KeyEventArgs e)
        {
            this.controlIsPressed = e.Control;
        }

        private void frmMain_Load(object sender, EventArgs e)
        {
            Thread t = new Thread(LoadData);
            t.Start();
        }

        private delegate void UpdateStatusLabelCallback(String text);
        private void UpdateStatusLabel(String text)
        {
            if (this.InvokeRequired)
            {
                UpdateStatusLabelCallback d = new UpdateStatusLabelCallback(UpdateStatusLabel);
                this.Invoke(d, text);
            }
            else
            {
                tslStatus.Text = text;
            }
        }

        private void LoadData()
        {
            UpdateStatusLabel("Printing zone tiles...");
            this.Invoke((MethodInvoker)delegate()
            {
                for (Int32 x = 0; x < 12; x++)
                {
                    for (Int32 y = 0; y < 12; y++)
                    {
                        ZoneTilePicureBox pb = new ZoneTilePicureBox();
                        pb.Name = "pb" + x + "_" + y;

                        pb.Size = new Size(32, 32);
                        pb.Location = new Point(x * 32, y * 32);
                        pb.MouseDown += new MouseEventHandler(pb_MouseDown);
                        pb.MouseMove += new MouseEventHandler(pb_MouseMove);
                        pb.MouseEnter += new EventHandler(pb_MouseEnterHover);
                        pb.MouseHover += new EventHandler(pb_MouseEnterHover);
                        pb.MouseUp += new MouseEventHandler(pb_MouseUp);
                        pb.Click += new EventHandler(pb_Click);
                        pb.Enabled = false;

                        pTileGrid.Controls.Add(pb);
                    }
                }

                UpdateStatusLabel("Filling combobox...");
                this.FillTextureComboBox();
            });

            UpdateStatusLabel("Ses done...");
        }

        private void pb_Click(object sender, EventArgs e)
        {
            if (cbMarkMode.Checked)
            {
                ZoneTilePicureBox pb = (ZoneTilePicureBox)sender;
                if (pb.BorderStyle == BorderStyle.None)
                {
                    pb.BorderStyle = BorderStyle.Fixed3D;
                }
                else
                {
                    pb.BorderStyle = BorderStyle.None;
                }
            }
        }

        #region drawing

        private void pb_MouseEnterHover(object sender, EventArgs e)
        {
            ZoneTilePicureBox pb = (ZoneTilePicureBox)sender;
            this.tslStatus.Text = String.Format("X: {0}, Y: {1}, Solid: {2}", pb.ZoneTile.X, pb.ZoneTile.Y, pb.ZoneTile.Solid);

            if (!cbMarkMode.Checked)
            {
                if (mouseMoveInMapTiles)
                {
                    if (pressedMouseButton == MouseButtons.Left)
                    {
                        if (!controlIsPressed)
                            if (selectedPbTile != null)
                            {
                                pb.BackgroundImage = (Tile)selectedPbTile.Tag;
                            }
                            else { }
                        else
                            pb.BackgroundImage = null;
                    }
                    else if (pressedMouseButton == MouseButtons.Right)
                    {
                        if (!controlIsPressed)
                            if (selectedPbTile != null)
                            {
                                pb.DecorationImage = (Tile)selectedPbTile.Tag;
                            }
                            else { }
                        else
                            pb.DecorationImage = null;
                    }
                }
            }
        }

        private void pb_MouseUp(object sender, MouseEventArgs e)
        {
            if (!cbMarkMode.Checked)
            {
                PictureBox pb = (PictureBox)sender;

                if (e.Button == MouseButtons.Left || e.Button == MouseButtons.Right)
                {
                    this.mouseMoveInMapTiles = false;
                    this.pressedMouseButton = MouseButtons.None;
                }
            }
        }

        private void pb_MouseMove(object sender, MouseEventArgs e)
        {
            if (!cbMarkMode.Checked)
            {
                PictureBox pb = (PictureBox)sender;
                pb.Capture = false;
            }
        }

        private void pb_MouseDown(object sender, MouseEventArgs e)
        {
            if (!cbMarkMode.Checked)
            {
                PictureBox pb = (PictureBox)sender;

                if (e.Button == MouseButtons.Left || e.Button == MouseButtons.Right)
                {
                    this.mouseMoveInMapTiles = true;
                    this.pressedMouseButton = e.Button;

                    pb_MouseEnterHover(sender, EventArgs.Empty);
                }
            }
        }

        #endregion

        private void mnuItemImportTexture_Click(object sender, EventArgs e)
        {
            if (ofdTexture.ShowDialog() == DialogResult.OK)
            {
                using (frmTextureImporter fti = new frmTextureImporter(ofdTexture.FileName))
                {
                    fti.ShowDialog();
                    Singleton.DrachamMapEditor.TextureManager.ImportTexture(ofdTexture.FileName, fti.UseTransparency, fti.SelectedColor);
                    FillTextureComboBox();
                }
            }
        }

        private void FillTextureComboBox()
        {
            Texture selectedTexture = (Texture)cbTextures.SelectedItem;
            cbTextures.Items.Clear();
            Int32 indexToSelect = 0;

            foreach (Texture t in Singleton.DrachamMapEditor.TextureManager.Textures)
            {
                if (selectedTexture != null && t.Name == selectedTexture.Name)
                    indexToSelect = cbTextures.Items.Add(t);
                else
                    cbTextures.Items.Add(t);
            }

            if (cbTextures.Items.Count > 0)
                cbTextures.SelectedIndex = indexToSelect;
        }

        private void cbTextures_SelectedIndexChanged(object sender, EventArgs e)
        {
            Texture texture = (Texture)cbTextures.SelectedItem;

            flpTiles.Controls.Clear();
            Int32 i = 0;
            foreach (Tile tile in texture.Tiles)
            {
                PictureBox pbTile = new PictureBox();
                pbTile.Name = "tile" + (i++);
                pbTile.Size = new Size(32, 32);
                pbTile.Image = tile.Image;
                pbTile.BorderStyle = BorderStyle.None;
                pbTile.Click += new EventHandler(pbTile_Click);
                pbTile.Tag = tile;

                flpTiles.Controls.Add(pbTile);
            }
        }

        private void pbTile_Click(object sender, EventArgs e)
        {
            PictureBox pbTile = (PictureBox)sender;

            //
            // no mark mode
            cbMarkMode.Checked = false;
            UnmarkZoneTiles();

            if (selectedPbTile != null)
            {
                selectedPbTile.BorderStyle = BorderStyle.None;
            }

            if (selectedPbTile != pbTile)
            {
                pbTile.BorderStyle = BorderStyle.Fixed3D;
                selectedPbTile = pbTile;
            }
            else
            {
                selectedPbTile = null;
            }
        }

        private void UnmarkZoneTiles()
        {
            foreach (ZoneTilePicureBox ztpb in pTileGrid.Controls)
            {
                ztpb.BorderStyle = BorderStyle.None;
            }
        }

        private void mnuItemNew_Click(object sender, EventArgs e)
        {
            using (frmSpecifyZone fsms = new frmSpecifyZone())
            {
                if (fsms.ShowDialog() == DialogResult.OK)
                {
                    this.zone = DrachamMapEditor.ZoneManager.CreateZone(fsms.Name, fsms.Id, fsms.EnterZoneText, fsms.SelectedWidth, fsms.SelectedHeight);

                    UpdateZoneTiles(0, 0);
                }
            }
        }

        private Int32 zoneTileStartX;
        private Int32 zoneTileStartY;

        private void UpdateZoneTiles(Int32 startX, Int32 startY)
        {
            this.zoneTileStartX = startX;
            this.zoneTileStartY = startY;

            for (Int32 x = 0; x < 12; x++)
            {
                for (Int32 y = 0; y < 12; y++)
                {
                    ZoneTilePicureBox ztpb = (this.pTileGrid.Controls["pb" + x.ToString() + "_" + y.ToString()] as ZoneTilePicureBox);

                    ztpb.ZoneTile = this.zone.Tiles[(startX + x), (startY + y)];
                    ztpb.Enabled = true;
                }
            }
        }

        private void mnuItemSave_Click(object sender, EventArgs e)
        {
            DrachamMapEditor.ZoneManager.SaveZone(this.zone);
        }

        private void mnuItemOpen_Click(object sender, EventArgs e)
        {
            using (frmSelectZone fsz = new frmSelectZone())
            {
                if (fsz.ShowDialog() == DialogResult.OK)
                {
                    this.zone = fsz.Zone;
                    UpdateZoneTiles(0, 0);
                }
            }
        }

        private void btnRight_Click(object sender, EventArgs e)
        {
            if (this.zoneTileStartX < (this.zone.Width - 21))
                this.zoneTileStartX++;

            UpdateZoneTiles(this.zoneTileStartX, this.zoneTileStartY);
        }

        private void btnLeft_Click(object sender, EventArgs e)
        {
            if (this.zoneTileStartX > 0)
                this.zoneTileStartX--;

            UpdateZoneTiles(this.zoneTileStartX, this.zoneTileStartY);
        }

        private void btnUp_Click(object sender, EventArgs e)
        {
            if (this.zoneTileStartY > 0)
                this.zoneTileStartY--;

            UpdateZoneTiles(this.zoneTileStartX, this.zoneTileStartY);
        }

        private void btnDown_Click(object sender, EventArgs e)
        {
            if (this.zoneTileStartY < (this.zone.Height - 12))
                this.zoneTileStartY++;

            UpdateZoneTiles(this.zoneTileStartX, this.zoneTileStartY);
        }

        private void cbMarkMode_CheckedChanged(object sender, EventArgs e)
        {
            if (cbMarkMode.Checked)
            {
                mnuItemWithSelectedTiles.Enabled = true;
            }
            else
            {
                mnuItemWithSelectedTiles.Enabled = false;
                UnmarkZoneTiles();
            }
        }

        private List<ZoneTilePicureBox> GetMarkedZoneTiles()
        {
            List<ZoneTilePicureBox> markedBoxes = new List<ZoneTilePicureBox>();

            foreach (ZoneTilePicureBox ztpb in pTileGrid.Controls)
            {
                if (ztpb.BorderStyle == BorderStyle.Fixed3D)
                {
                    markedBoxes.Add(ztpb);
                }
            }

            return markedBoxes;
        }

        private void mnuItemMakeSolid_Click(object sender, EventArgs e)
        {
            List<ZoneTilePicureBox> markedBoxes = GetMarkedZoneTiles();

            markedBoxes.ForEach(delegate(ZoneTilePicureBox box)
            {
                box.ZoneTile.Solid = true;
            });
        }

        private void mnuItemBuildMaps_Click(object sender, EventArgs e)
        {
            using (frmMapCompiler fmc = new frmMapCompiler())
            {
                tslStatus.Text = "Compiling maps";

                fmc.ShowDialog();

                tslStatus.Text = "Maps compiled";
            }
        }

        private void mnuItemOnEnterTeleport_Click(object sender, EventArgs e)
        {
            List<ZoneTilePicureBox> markedTiles = GetMarkedZoneTiles();
            if (markedTiles.Count > 0)
            {
                ZoneTilePicureBox ztpb = markedTiles[0];
                OnEnter oe = ztpb.ZoneTile.GetOrCreateEvent<OnEnter>(typeof(OnEnter));

                Teleport tp = oe.GetAction<Teleport>(typeof(Teleport));
                using (frmTileEventTeleport ftep = new frmTileEventTeleport(ztpb.ZoneTile, tp))
                {
                    if (ftep.ShowDialog() == DialogResult.OK)
                    {
                        if (tp == null)
                        {
                            tp = new Teleport();

                            oe.Actions.Add(tp);
                        }

                        tp.X = ftep.X;
                        tp.Y = ftep.Y;
                        tp.Zone = ftep.Zone;
                    }
                }
            }
        }

        private void mnuItemRemoveSolid_Click(object sender, EventArgs e)
        {
            List<ZoneTilePicureBox> markedBoxes = GetMarkedZoneTiles();

            markedBoxes.ForEach(delegate(ZoneTilePicureBox box)
            {
                box.ZoneTile.Solid = false;
            });
        }

        private void setMobSpawnPointToolStripMenuItem_Click(object sender, EventArgs e)
        {
            List<ZoneTilePicureBox> markedBoxes = GetMarkedZoneTiles();

            foreach (ZoneTilePicureBox ztpb in markedBoxes)
            {
                using (frmInsertMobileObjectSpawnPoint fimosp = new frmInsertMobileObjectSpawnPoint(ztpb.ZoneTile))
                {
                    if (fimosp.ShowDialog() == DialogResult.OK)
                    {
                        ztpb.ZoneTile.SpawnPoint = new Dracham.MapEditor.Zones.Extras.SpawnPoint(fimosp.Type, fimosp.Id, fimosp.Interval);
                    }
                }
            }
        }
    }
}
